;; The first three lines of this file were inserted by DrRacket. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname |4|) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ())))
;; problem 2 set 06

;; ALGORITHM:
;; 1. check if the given S-expression represents a valid command by
;;    checking for possible combinations of symbols
;;    and the associated arguments needed.
;; 2. if the S-expression is found to be an invalid representation of command
;;    the return false.
;; 3. if the S-expression is a valid representation of command,
;;    then convert the S-expression to the internal syntax, traversing through
;;    whole of the S-expression and converting each part to a corresponding
;;    internal syntax command in the following manner.
;;    the arguments needed by each command are clubbed together to form
;;    a command in internal syntax.

(require 2htdp/image)
(require rackunit)
(require "extras.rkt")
(require "1.rkt")
(provide decode check-if-valid-sexp? decode-ext-cmd)


;; An SexpOfAtom is either
;; -- Symbol
;;    Interp: a symbol
;; -- Number
;;    Interp: a number 
;; -- a ListOf<SexpOfAtom>
;;    Interp: a sequence of SexpOfAtom
;;
;; Template:
;; sexpat-fn : SexpOfAtom -> ??
;;(define (sexpat-fn sexp-at)
;;  (cond
;;    [(symbol? sexp-at) ...]
;;    [(number? sexp-at) ...]
;;    [else (... (lst-sexpat-fn sexp-at))]))


;; ListOf<SexpOfAtom> is either
;; -- empty
;;    Interp: no element
;; -- (cons SexpOfAtom ListOf<SexpOfAtom>)
;;    Interp: a sequence where the first element is epresented by SexpOfAtom
;;    and rest of the elements are represented by ListOf<SexpOfAtom>.
;;
;; Template:
;; lst-sexpat-fn : ListOf<SexpOfAtom> -> ??
;;(define (lst-sexpat-fn sexp-lst)
;;  (cond 
;;    [(empty? sexp-lst) ...]
;;    [else (... (sexpat-fn (first sexp-lst))
;;               (lst-sexpat-fn (rest sexp-lst)))]))


;; ExternalMove is a SexpOfAtom and can be one of the following
;; -- 'forward
;;     Interp : Represents a SexpOfAtom, that can be translated into
;;              a Unit-Ext-Cmd (a valid command in external syntax)
;; -- 'left 
;;     Interp : Represents a SexpOfAtom, that can be translated into
;;              a Unit-Ext-Cmd (a valid command in external syntax)
;; -- 'left
;;     Interp : Represents a SexpOfAtom, that can be translated into
;;              a Unit-Ext-Cmd (a valid command in external syntax)
;; -- 'do-times
;;     Interp : Represents a SexpOfAtom, that can be translated into
;;              a Unit-Ext-Cmd (a valid command in external syntax)
;; -- 'if-facing-edge
;;     Interp : Represents a SexpOfAtom, that can be translated into
;;              a Unit-Ext-Cmd (a valid command in external syntax)
;; -- 'while-not-at-edge-do
;;     Interp : Represents a SexpOfAtom, that can be translated into
;;              a Unit-Ext-Cmd (a valid command in external syntax)
;; --  any other symbol
;;     Interp : any other symbol is ignored, which doesnot represent a valid
;;              command in internal syntax.
;;
;; Template:
;; external-move-fn : ExternalMove -> ??
;;(define (external-move-fn external-move)
;;  (cond
;;    [(symbol=? external-move 'forward)...]
;;    [(symbol=? external-move 'left)...]
;;    [(symbol=? external-move 'right)...]
;;    [(symbol=? external-move 'do-times)...] 
;;    [(symbol=? external-move 'if-facing-edge) ...]
;;    [(symbol=? external-move 'while-not-at-edge-do)...]
;;    [else ...]))

;; NonNegInt represents any non-negative integer.

;; A valid command in external syntax is represented by Unit-Ext-Cmd.

;; Unit-Ext-Cmd is valid representaion of command in exteral syntax & is one of
;; -- (list 'forward NonNegInt)
;;    Interp: represents a SexpOfAtom, and consists of
;;            symbol forward(ExternalMove) and a non-negative Integer.
;; -- (list 'left NonNegInt)
;;    Interp: represents a SexpOfAtom, and consists of 
;;            symbol left (ExternalMove) and  a non-negative Integer.
;; -- (list 'right NonNegInt)
;;    Interp: represents a SexpOfAtom, and consists of 
;;            symbol right (ExternalMove) and  a non-negative Integer.
;; -- (list 'do-times NonNegInt Unit-Ext-Cmd)
;;    Interp: represents a SexpOfAtom, and consists of symbol 
;;            do-times (ExternalMove), a non-negative Integer 
;;            and an ExtCmd (ListOf<SexpOfAtom>).
;; -- (list 'if-facing-edge ExtCmd Unit-Ext-Cmd)
;;    Interp: represents a SexpOfAtom, and consists of symbol 
;;            if-facing-edge (ExternalMove) and two ExtCmd (ListOf<SexpOfAtom>).
;; -- (list 'while-not-facing-edge-do Unit-Ext-Cmd)
;;    Interp: represents a SexpOfAtom and consists of symbol 
;;            while-not-facing-edge-do (ExternalMove) & 
;;            ExtCmd (ListOf<SexpOfAtom>)
;; -- ExtCmd
;;    Interp : represents a list of commands in external syntax. 
;;
;; Template
;; unit-ext-cmd-fn : Unit-Ext-Cmd -> ??
;;(define (unit-ext-cmd-fn unit-ext-cmd)
;;  (cond
;;    [(symbol=? (first unit-ext-cmd) 'forward)
;;     (... (second unit-ext-cmd))]
;;    [(symbol=? (first unit-ext-cmd) 'left)
;;     (... (second unit-ext-cmd)) ]
;;    [(symbol=? (first unit-ext-cmd) 'right) 
;;     (... (second unit-ext-cmd)) ]
;;    [(symbol=? (first unit-ext-cmd) 'do-times) 
;;     (... (second unit-ext-cmd) (third unit-ext-cmd))]
;;    [(symbol=? (first unit-ext-cmd) 'if-facing-edge) 
;;     (... (second unit-ext-cmd) (third unit-ext-cmd))]
;;    [(symbol=? (first ext-cmd) 'while-not-facing-edge-do)
;;     (... (second unit-ext-cmd))]
;;    [else (ext-cmd-fn unit-ext-cmd)]))

;; An ExtCmd is the valid representation of the external syntax
;; of command and is either
;; -- empty
;;    Interp: no command
;; -- (cons Unit-Ext-Cmd ExtCmd)
;;    Interp: representing a sequence where the first element is Unit-Ext-Cmd
;;     and subsequent elements are represented by ExtCmd
;;
;; Template:
;; ext-cmd-fn : ExtCmd -> ??
;;(define (ext-cmd-fn ext-cmd)
;;  (cond 
;;    [(empty? ext-cmd) ...]
;;    [else (...(unit-ext-cmd (first ext-cmd)) 
;;              (ext-cmd-fn (rest ext-cmd)))]))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; A Cmd is either
;; -- Forward
;;    Interp: internal syntax of forward command
;; -- Left
;;    Interp: internal syntax of left command
;; -- Right
;;    Interp: internal syntax of right command
;; -- Do-times
;;    Interp: internal syntax of do-times command
;; -- If-facing-edge
;;    Interp: internal syntax of if-facing-edge command
;; -- While-not-facing-edge-do
;;    Interp: internal syntax of while-not-facing-edge-do command
;; -- ListOf<Cmd> 
;;    Interp: a list of commands in internal syntax

;; Template:
;; cmd-fn : Cmd -> ??
;;(define (cmd-fn cmd)
;;  (cond
;;    [(forward? cmd) (...(forward-fn cmd))] 
;;    [(left? unitcmd) (...(left-fn cmd))] 
;;    [(right? unitcmd) (...(right-fn cmd))]
;;    [(do-times? unitcmd) (...(dotimes-fn cmd))] 
;;    [(if-facing-edge? unitcmd) (...(if-facing-edge cmd))] 
;;    [(while-not-facing-edge-do? unitcmd) 
;;     (...(while-not-facing-edge-do-fn cmd))]
;;    [else (lst-cmd-fn cmd)]))


;; ListOf<Cmd> is the internal syntax of a list of commands and is either
;; -- empty
;;    Interp: no command
;; -- (cons Cmd ListOf<Cmd>) 
;;    Interp: a list whose first element is a Cmd and rest 
;;    of the elements are represented by ListOf<Cmd>.
;;
;; Template:
;; lst-cmd-fn : ListOf<Cmd> -> ??
;;(define (lst-cmd-fn lst-cmd)
;;  (cond 
;;    [(empty? cmd) ...]
;;    [else (...(cmd-fn (first lst-cmd)) 
;;              (lst-cmd-fn (rest lst-cmd)))]))

;; Maybe<Cmd> is either
;; -- false
;;    Interp: false when SexpOfAtom is not a valid 
;;    representation of command
;; -- Cmd
;;    Interp: internal syntax of valid command
;;
;; Template:
;; maybecmd-fn : Maybe<Cmd> -> ??
;;(define (maybecmd-fn maybecmd)
;;  (cond
;;    [(boolean? maybecmd) ...]
;;    [else (... (cmd-fn maybecmd))]))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define first-of-cmd first)
(define second-of-cmd second)
(define third-of-cmd third)

(define MAX-LENGTH 2)
(define MIN-LENGTH 1)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; decode : SexpOfAtom -> Maybe<Cmd>
;; takes a SexpOfAtom and returns a 
;; command in internal syntax iff the given SexpOfAtom represents a 
;; s-expression that can can be traslated to a valid command in internal
;; syntax, else returns false.
;; Examples: See tests below
;; Strategy: Function composition
(define (decode sexp-at)
  (if (check-if-valid-sexp? sexp-at)
    (decode-ext-cmd sexp-at) #f))

;; check-if-valid-sexp? : SexpOfAtom -> Boolean
;; takes a sexp and and returns true iff the given sexp translates to a valid
;; command in internal syntax.
;; Examples : 
;; (check-if-valid-sexp? (list)) :  true
;; (check-if-valid-sexp? 10 'forward) :  false
;; (check-if-valid-sexp? (list 'forward 10)) :  true
;; Strategy : General recursion
;; Terminaion Argument :
;; the size of an s-expression decreases on each recursive call to itself,
;; the function being called recursively by helper functions.
;; For a s-expression sexp-at, when the size equals zero, the recursion halts.
;; (second sexp-at), (third sexp-at) or (rest sexp-at) each have smaller size
;; than sexp-at. For trivial cases, where given SexpOfAtom is either a number
;; or a symbol the function gives a trivial solution. On each recursive call 
;; as the size decrements everytime, we inch closer to the trivial solution.
(define (check-if-valid-sexp? sexp-at)
  (cond 
    [(symbol? sexp-at) #f]
    [(number? sexp-at) #f]
    [else (check-if-valid-lst? sexp-at)]))

;; check-if-valid-lst? : ListOf<SexpOfAtom> -> Boolean
;; takes a list of SexpOfAtom in form of S-expression and returns true iff 
;; the given list is a valid representation of a command in external syntax.
;; Examples : See tests below
;; Strategy : Structural decomposition on sexp-lst : ListOf<SexpOfAtom>
;; (part of general recursion)
;; Termination argument : 
;; the size of an s-expression decreases on each recursive call.
;; For a s-expression sexp-lst, when the size equals zero, the recursion halts.
;; (first sexp-lst) is taken and checked if it 
;; represents a valid command in external syntax. later recursive calls check
;; for (rest sexp-lst).
(define (check-if-valid-lst? sexp-lst)
  (cond 
    [(empty? sexp-lst) #t]
    [else 
     (if (symbol? (first sexp-lst))
         (is-valid? (first sexp-lst) (rest sexp-lst))
         (helper-check-if-valid-lst? (first sexp-lst) (rest sexp-lst)))]))

;; helper-check-if-valid-lst? : SexpOfAtom ListOf<SexpOfAtom> -> Boolean
;; takes a sexp of atom and a S-expression & returns true
;; iff the given S-expression reprsents a valid command in external syntax.
;; Examples : See tests below
;; Strategy : Structural decomposition on rst : ListOf<SexpOfAtom>
;; (part of general recursion)
;; Termination argument : 
;; the size of an s-expression decreases on each recursive call to the function.
;; where fst,rst each will have smaller size than sexp-lst.
(define (helper-check-if-valid-lst? sexp-at sexp-lst)
  (cond
    [(empty? sexp-lst) (check-if-valid-sexp? sexp-at)]  
    [else (and 
           (not (ormap (lambda (x) (or (number? x)(symbol? x))) sexp-lst))
           (check-if-valid-sexp? sexp-at) (check-if-valid-sexp? sexp-lst))]))


;; is-valid? : ExternalMove ListOf<SexpOfAtom> -> Boolean
;; takes a external-move and a S-expression
;; and returns true iff the S-expression with the external-move 
;; is a valid represenatation of a command in external syntax.
;; Examples : See test cases below
;; Startegy : Strutural decomposition on external-move : ExternalMove
;; (part of general recursion)
;; Termination argument : 
;; the size of S-expression sexp-lst decreases on each recursive call
;; (here the recirsive calls are made by the helper functions)
;; where if we denote the decremented size of sexp-lst by sexp-lst-decr,
;; then each time sexp-lst-decr will have smaller size than sexp-lst.
(define (is-valid? external-move sexp-lst)
  (cond
    [(symbol=? external-move 'forward) (unit-ext-cmd-helper sexp-lst)]
    [(symbol=? external-move 'right) (unit-ext-cmd-helper sexp-lst)]
    [(symbol=? external-move 'left) (unit-ext-cmd-helper sexp-lst)]
    [(symbol=? external-move 'do-times) (dotimes-helper sexp-lst)]
    [(symbol=? external-move 'if-facing-edge) (if-facing-edge-helper sexp-lst)]
    [(symbol=? external-move 'while-not-facing-edge-do) 
     (while-not-facing-edge-do-helper sexp-lst)]
    [else #f]))


;; while-not-facing-edge-do-helper : ListOf<SexpOfAtom> -> Boolean
;; takes a S-expression and returns true iff is a valid 
;; representation of a command in external syntax.
;; Examples : See tests below
;; Strategy :  Strutural decomposition on sexp-lst :  ListOf<SexpOfAtom>
;; (part of general recursion)
;; Termination argument : 
;; the size of an s-expression decreases on each recursive call.
;; For a s-expression sexp-lst, when the size equals zero, the recursion halts.
;; (first sexp-lst) is taken and checked if it 
;; represents a valid command in external syntax.
(define (while-not-facing-edge-do-helper sexp-lst)
  (cond
    [(empty? sexp-lst) #f]
    [else (and (equal? (length sexp-lst) MIN-LENGTH)
               (check-if-valid-sexp? (first sexp-lst)))]))
 
;; if-facing-edge-helper : ListOf<SexpOfAtom> -> Boolean
;; takes a S-expression and returns true iff it is a valid 
;; representation of a command in external syntax.
;; Examples : See tests below
;; Strategy :  Strutural decomposition on sexp-lst :  ListOf<SexpOfAtom>
;; (part of general recursion)
;; Termination argument : 
;; the size of an S-expression decreases on each recursive call.
;; such that, when the size equals zero, the recursion halts.
;; (first sexp-lst) and (rest sexp-lst) is taken and checked if it 
;; represents a valid command in external syntax, 
;; and have size smaller than sexp-lst.
(define (if-facing-edge-helper sexp-lst)
  (cond
    [(empty? sexp-lst) #f]
    [else (and (equal? (length sexp-lst) MAX-LENGTH)
               (check-if-valid-sexp? (first sexp-lst))
               (check-if-valid-sexp? (rest sexp-lst)))]))


;; dotimes-helper : ListOf<SexpOfAtom> -> Boolean
;; takes a list of sexp and returns true iff the given list is a valid 
;; representation of a comand in nternal syntax.
;; Invariant : in the command representation, the number is a 
;; non-negative interger.
;; Examples : See tests below
;; Strategy :  Strutural decomposition on sexp-lst :  ListOf<SexpOfAtom>
;; (part of general recursion)
;; Termination argument : 
;; the size of an S-expression decreases on each recursive call,such that
;; when the size equals zero, the recursion halts.
;; (first sexp-lst) and (rest sexp-lst) is taken and checked if it 
;; represents a valid command in external syntax, 
;; and have size smaller than sexp-lst.
(define (dotimes-helper sexp-lst)
  (cond
    [(empty? sexp-lst) #f]
    [else (and (valid-number? (first sexp-lst))
               (equal? (length sexp-lst) MAX-LENGTH)
               (check-if-valid-sexp? (rest sexp-lst)))]))


;; unit-ext-cmd-helper : ListOf<SexpOfAtom> -> Boolean
;; takes a S-expression and returns true iff it is a valid 
;; representation of a command in external syntax.
;; Invariant : in the command representation, the number is a 
;; non-negative interger.
;; Examples : See tests below
;; Strategy :  Strutural decomposition on sexp-lst :  ListOf<SexpOfAtom>
;; (part of general recursion)
;; Termination argument : 
;; the size of an S-expression decreases on each recursive call, such that
;; when the size equals zero, the recursion halts.
;; (first sexp-lst) and (rest sexp-lst) is taken and checked if it 
;; represents a valid command in external syntax, 
;; and have size smaller than sexp-lst.
(define (unit-ext-cmd-helper sexp-lst)
  (cond
    [(empty? sexp-lst) #f]
    [else (and (equal? (length sexp-lst) MIN-LENGTH)
               (valid-number? (first sexp-lst)))]))

;; valid-number? : SexpOfAtom -> Boolean
;; takes a sexp of atom and returns true iff the sexp is a non negaive integer
;; otherwise returns false
;; Examples : See tests below
;; Strategy : Function Composition (part of general recursion)
;; Termination argument : 
;; the size of an S-expression decreases on each recursive call, such that
;; when the size equals zero, the recursion halts.
;; (first sexp-lst) and (rest sexp-lst) is taken and checked if it 
;; represents a valid command in external syntax, 
;; and have size smaller than sexp-lst.
(define (valid-number? sexp-at)
  (if (and (number? sexp-at)
           (not (negative? sexp-at))) #t #f))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; decode-ext-cmd : ListOf<SexpOfAtom> -> Cmd
;; takes a valid S-expression in external syntax and 
;; returns a command in internal syntax
;; Examples: See tests below
;; Startegy : General recursion
;; Termination Argument : the length of the S-expression sexp-lst is always
;; non-negative such that on every recursive call, the size decreases.
;; In the trivial solution, the size is zero and recursion halts
;; for non-trivial case, (first sexp-lst),(second sexp-lst) and (rest sexp-lst)
;; are parts of sexp-lst, less than sexp-lst itself.
(define (decode-ext-cmd sexp-lst)
  (cond 
    [(empty? sexp-lst) empty]
    [else (if (symbol? (first sexp-lst))
              (decode-act (first sexp-lst) sexp-lst) 
              (decode-seq-ext-cmd sexp-lst))]))
    
;; decode-act : ExternalMove  ListOf<SexpOfAtom> -> Cmd
;; takes a valid move and S-expression that is a valid representation 
;; of a command in external syntax and returns a command in internal syntax.
;; Examples : See tests below
;; Strategy : Structural decomposition on external-move : ExternalMove
;; (part of general recursion)
;; Termination Argument :  the length of the S-expression ext-cmd is always
;; non-negative such that on every recursive call, the size decreases.
;; where (first sexp-lst), (second sexp-lst), (third sexp-lst) are always less
;; than sexp-lst.
(define (decode-act external-move sexp-lst)
  (cond  
    [(symbol=? external-move 'forward) 
     (make-forward (second sexp-lst))]
    [(symbol=? external-move 'left) 
     (make-left (second sexp-lst))]
    [(symbol=? external-move 'right) 
     (make-right (second sexp-lst))]
    [(symbol=? external-move 'do-times) 
     (make-do-times (second sexp-lst) 
                    (decode-ext-cmd (third sexp-lst)))]
    [(symbol=? external-move 'if-facing-edge)
     (make-if-facing-edge (decode-ext-cmd (second sexp-lst)) 
                          (decode-ext-cmd (third sexp-lst)))]
    [(symbol=? external-move 'while-not-facing-edge-do)
     (make-while-not-facing-edge-do (decode-ext-cmd (second sexp-lst)))]
    [else #f]))

;; decode-seq-ext-cmd : ListOf<SexpOfAtom> -> Cmd
;; takes a valid external syntax of sequence command and returns a 
;; command in internal syntax
;; Examples: See tests below
;; Strategy: Higher order Function composition (part of general recursion)
;; Termination argument : On each recursive call, size of seq decreases,
;; where (first seq), (second seq) and (rest seq) are always less than seq
(define (decode-seq-ext-cmd seq)
  (map decode-ext-cmd seq))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; tests

;; test for empty S-expression
(check-equal?
 (decode empty)
 empty
 "given an empty S-expression, should return empty")

;; test for forward symbol for a given SexpOfAtom
(check-equal?
 (decode 'forward)
 #f
 "given an symbol as S-expression, should return false")

;; test for left symbol for a given SexpOfAtom
(check-equal?
 (decode 'left)
 #f
 "given an symbol as S-expression, should return false")

;; test for right symbol for a given SexpOfAtom
(check-equal?
 (decode 'right)
 #f
 "given an symbol as S-expression, should return false")
;; test for a number 
(check-equal?
 (decode 3)
 #f
 "given a number, should return false")

;; test for a list containing a number 
(check-equal?
 (decode (list 3))
 #f
 "given a list containing a number, should return false")

;; test for a invalid command in external syntax  
(check-equal?
 (decode (list 'forw 3))
 #f
 "given a command containing a invalid symbol and a number, 
should return false")
;;;;;;;;

;; test for a list containing a 'forward symbol and a non-negative integer
(check-equal?
 (decode (list 'forward 2))
 (make-forward 2)
 "given a list containing a 'forward symbol and a non-negative integer, 
  should return a make-forward")

;; test for a list containing a 'forward symbol and a negative integer
(check-equal?
 (decode (list 'forward -2))
 #f
 "given a list containing a 'forward symbol and a negative integer, 
  should return false")

;; test for a list containing a 'forward symbol and two numbers
(check-equal?
 (decode (list 'forward 2 2))
 #f
 "given a list  containing a 'forward symbol and two numbers, 
  should return false")

;; test for a list containing a 'left symbol and a non-negative number
(check-equal?
 (decode (list 'left 2))
 (make-left 2)
 "given a list  containing a 'left symbol and a number, 
  should return a make-left")

;; test for a list containing a 'left symbol and a negative number
(check-equal?
 (decode (list 'left -2))
 #f
 "given a list  containing a 'left symbol and a number, 
  should return false")

;; test for a list containing a 'right symbol and a non-negative number
(check-equal?
 (decode (list 'right 2))
 (make-right 2)
 "given a list containing a 'right symbol and a number, 
  should return a make-right")

;; test for a list containing a 'right symbol and a negative number
(check-equal?
 (decode (list 'right -2))
 #f
 "given a list containing a 'right symbol and a number, 
  should return false")

;; test for a list containing a 'left symbol
(check-equal?
 (decode (list 'left))
 #f
 "given a list  containing a 'left symbol, 
  should return false")

;; test for a list containing a 'right symbol
(check-equal?
 (decode (list 'right))
 #f
 "given a list  containing a 'right symbol, 
  should return false")

;;;;;;;;

;; test for a list containing a 'do-times symbol
(check-equal?
 (decode (list 'do-times))
 #f
 "given a list  containing a 'do-times symbol only, 
  should return false")

;; test for a list containing a 'do-times symbol and a number only
(check-equal?
 (decode (list 'do-times 2))
 #f
 "given a list  containing a 'do-times symbol and a number only, 
  should return false")

;; test for command 'do-times when the inside command is empty
(check-equal?
 (decode (list 'do-times 2 empty))
 (make-do-times 2 empty)
 "given a list  containing a 'do-times symbol and a number & empty command list
  should return a valid do times command in internal syntax")

;; test for command 'do-times when the inside command is empty
;; and a negative integer
(check-equal?
 (decode (list 'do-times -2 empty))
 #f
 "given a list  containing a 'do-times symbol and a negative number & empty 
  command list should return a valid do times command in internal syntax")

;; test for a list containing a 'do-times symbol and a valid 
;; left command representation
(check-equal?
 (decode (list 'do-times 2 (list 'left 10)))
 (make-do-times 2 (make-left 10))
 "given a list  containing a 'do-times symbol and a valid 
 left command representation, should return make-do-times")

;; test for a list containing a 'do-times symbol and
;; number is negative
(check-equal?
 (decode (list 'do-times 2 (list 'left -10)))
 #f
 "given a list  containing a 'do-times symbol and a 
 left command representation with negative number, should return false")

;; test for  a do times, when the ext command is itself a list of sexp
(check-equal?
(decode (list 'do-times 2 
              (list (list 'forward 2) 
                    (list 'if-facing-edge (list 'left 10) (list 'right 2)))))
(make-do-times 2 (list (make-forward 2) 
                       (make-if-facing-edge (make-left 10) (make-right 2))))
"should return a decode command")

;; test for a if-facing-edge symbol only
(check-equal?
 (decode (list 'if-facing-edge ))
 #f
 "given a list containing a 'if-facing-edge symbol 
  should return false")

;; test for a list containing a 'if-facing-edge symbol and a number
(check-equal?
 (decode (list 'if-facing-edge 2))
 #f
 "given a list containing a 'if-facing-edge symbol and a number, 
  should return false")


;; test for a list containing a 'if-facing-edge symbol and an empty list
(check-equal?
 (decode (list 'if-facing-edge empty))
 #f
 "given a list containing a 'if-facing-edge symbol and an empty list, 
  should return false")

;; test for a list containing a 'if-facing-edge symbol and an empty list
;; of commands as cmd1 and cmd2
(check-equal?
 (decode (list 'if-facing-edge empty empty))
 (make-if-facing-edge empty empty)
 "given a list containing a 'if-facing-edge symbol and an empty list, 
  should return false")

;; test for if-facing-edge contaning only a single external command
(check-equal?
 (decode (list 'if-facing-edge (list 'forward 10)))
 #f
 "given a list containing a 'if-facing-edge symbol and a single 
external command,should return false")

;; test for a list containing a 'if-facing-edge symbol and a symbol 'forward
(check-equal?
 (decode (list 'if-facing-edge 'forward))
 #f
 "given a list containing a 'if-facing-edge symbol and a symbol forward, 
  should return false")

;; test for a list containing a 'if-facing-edge symbol and two valid
;; commands in external syntax
(check-equal?
 (decode (list 'if-facing-edge (list 'forward 2) (list 'left 3)))
 (make-if-facing-edge (make-forward 2) (make-left 3))
 "given a list containing a 'if-facing-edge symbol and two valid
  commands in external syntax, should return make-if-facing-edge")

;; test for a list containing a 'if-facing-edge symbol and two 
;; commands in external syntax, where one command has  anegative number
(check-equal?
 (decode (list 'if-facing-edge (list 'forward 2) (list 'left -3)))
 #f
 "given a list containing a 'if-facing-edge symbol and two commands in external
  syntax, one of them having a negative number, should return false")
;;;;;;;;;;;;
;; test for a list containing a 'while-not-facing-edge-do symbol
(check-equal?
 (decode (list 'while-not-facing-edge-do))
 #f
 "given a list containing a 'while-not-facing-edge-do, 
  should return false")

;; test for a list containing a 'while-not-facing-edge-do symbol
;; and an empty command list
(check-equal?
 (decode (list 'while-not-facing-edge-do empty))
 (make-while-not-facing-edge-do empty)
 "given a list containing a 'while-not-facing-edge-do, 
  should return equivalent command in internal syntax")

;; test for a list containing a 'while-not-facing-edge-do symbol and a number
(check-equal?
 (decode (list 'while-not-facing-edge-do 10))
 #f
 "given a list containing a 'while-not-facing-edge-do, 
  should return false")


;; test for a list containing a 'while-not-facing-edge-do symbol and a valid
;; command in external syntax
(check-equal?
 (decode (list 'while-not-facing-edge-do (list 'forward 2)))
 (make-while-not-facing-edge-do (make-forward 2))
 "given a list containing a 'while-not-edge and a valid
  command in external syntax, should return make-while-not-at-edge")

;; test for a list containing a 'while-not-facing-edge-do symbol and a
;; command in external syntax with negative number
(check-equal?
 (decode (list 'while-not-facing-edge-do (list 'forward -2)))
 #f
 "given a list containing a 'while-not-edge and a  command in external syntax
 with negative number, should return false")

;;;;;;;;

;; mixed lists tests
(check-equal?
(decode 
 (list 'do-times (list (list 'forward 2) 
                       (list 'if-facing-edge (list 'left) (list 'right)))))
#f
"should return false")

(check-equal?
(decode (list 2 (list 2 (list 'if-at-edge (list 'left 10) (list 'right 10)))))
#f
"should return false")

(check-equal?
(decode (cons (cons 'left empty) (cons (cons 2 empty) empty)))
#f
"should return false")

;; test when the ext command is itself a list of SexpOfAtom
(check-equal?
(decode (list (list 'forward 10) 
              (list 'do-times 2 (list (list 'forward 2) 
                                      (list 'if-facing-edge 
                                            (list 'left 10) (list 'right 2))))
              (list 'if-facing-edge (list 'left 10) (list 'right 10))))
(list
 (make-forward 10)
 (make-do-times 
  2 (list (make-forward 2) 
          (make-if-facing-edge (make-left 10) (make-right 2))))
 (make-if-facing-edge (make-left 10) (make-right 10)))
"should return false")


;; test for decode-act function:
(check-equal?
 (decode-act 'backward (list 'left 10))
 #f
 "for a valid-move other than forward, left, right, do-times
 if-at-edge, while-not-at-edge-do, a false value is returned 
as this doesnot corrospond to any of the given valid commands in 
internal syntax")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
